package org.example.util;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class HttpRequest {

    private static final String URL_PREFIX = "http://";
    /**
     * 连接配置
     */
    private static RequestConfig requestConfig;
    /**
     * https证书
     */
    private static SSLConnectionSocketFactory ssl;
    /**
     * 连接管理器
     */
    private static PoolingHttpClientConnectionManager connectionManager;


    static {
        try {
            ssl = new SSLConnectionSocketFactory(SSLContexts.custom().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build(), NoopHostnameVerifier.INSTANCE);
            requestConfig = RequestConfig.custom().setConnectTimeout(100).setSocketTimeout(1000).setConnectionRequestTimeout(1000).build();
            connectionManager = new PoolingHttpClientConnectionManager();
            connectionManager.setValidateAfterInactivity(1000);
            connectionManager.setDefaultMaxPerRoute(100);
            connectionManager.setMaxTotal(100);
        } catch (Exception e) {

        }
    }

    private String url;

    private String params;

    private HttpMethod method;

    private Map<String, String> headers;

    public HttpRequest(String url, HttpMethod method) {
        this.url = transformedUrl(url);
        this.headers = new HashMap<>();
        this.method = method;
    }

    public HttpRequest(String url, HttpMethod method, Map<String, String> headers) {
        this.headers = Optional.ofNullable(headers).orElseGet(HashMap::new);
        this.url = transformedUrl(url);
        this.method = method;
    }

    public HttpRequest(String url, HttpMethod method, Map<String, String> headers, String params) {
        this.headers = Optional.ofNullable(headers).orElseGet(HashMap::new);
        this.url = transformedUrl(url);
        this.params = params;
        this.method = method;
    }

    public HttpRequest addHeader(String name, String value) {
        this.headers.put(name, value);
        return this;
    }

    public static String doGet(String url) {
        return new HttpRequest(url, HttpMethod.GET).exec();
    }

    public static String doGet(String url, Map<String, String> headers) {
        return new HttpRequest(url, HttpMethod.GET, headers).exec();
    }

    public static String doGet(String url, Map<String, Object> params, Map<String, String> headers) {
        if (null == params) {
            return new HttpRequest(url, HttpMethod.GET, headers).exec();
        }
        StringBuffer sb = new StringBuffer();
        params.forEach((k, v) -> sb.append("&").append(k).append("=").append(v));
        url = sb.replace(0, 1, "?").insert(0, url).toString();
        return new HttpRequest(url, HttpMethod.GET, headers).exec();
    }

    public static String doPost(String url, Map<String, Object> params) {
        List<BasicNameValuePair> nameValuePairs = params.entrySet().stream().map(v -> new BasicNameValuePair(v.getKey(), String.valueOf(v.getValue()))).collect(Collectors.toList());
        String content = URLEncodedUtils.format(nameValuePairs, "UTF-8");
        return new HttpRequest(url, HttpMethod.POST, null, content).exec();
    }

    public static String doPost(String url, Map<String, Object> params, Map<String, String> headers) {
        List<BasicNameValuePair> nameValuePairs = params.entrySet().stream().map(v -> new BasicNameValuePair(v.getKey(), String.valueOf(v.getValue()))).collect(Collectors.toList());
        String content = URLEncodedUtils.format(nameValuePairs, "UTF-8");
        return new HttpRequest(url, HttpMethod.POST, headers, content).exec();
    }

    public static String doPost(String url, String json, Map<String, String> headers) {
        if (null == headers) {
            headers = new HashMap<>();
        }
        headers.put("Content-Type", "application/json");
        return new HttpRequest(url, HttpMethod.POST, headers, json).exec();
    }

    public String exec() {
        HttpUriRequest request = this.method.request(this);
        headers.forEach(request::addHeader);

        HttpClient httpClient = this.url.startsWith("https") ? HttpClients.createDefault() :
                HttpClients.custom().setSSLSocketFactory(ssl).setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).build();

        String result = "";
        HttpResponse response = null;
        try {
            response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8);
            }
        } catch (IOException ignored) {
            System.err.println("出现异常");
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                }
            }
        }
        return result;
    }

    public String transformedUrl(String url) {
        if (null == url || "".equals(url)) {
            throw new RuntimeException("URL连接不正确");
        }
        if (url.startsWith("http") || url.startsWith("https")) {
            return url;
        }
        return URL_PREFIX + url;
    }

    enum HttpMethod {
        GET {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                if (null != request.params && !"".equals(request.params)) {
                    request.url = request.url + "?" + request.params;
                }
                return new HttpGet(request.url);
            }
        },
        POST {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                HttpPost httpPost = new HttpPost(request.url);
                httpPost.setEntity(new StringEntity(request.params, StandardCharsets.UTF_8));
                return httpPost;
            }
        },
        PUT {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                return new HttpPut(request.url);
            }
        },
        DELETE {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                return new HttpDelete(request.url);
            }
        },
        HEAD {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                return new HttpHead(request.url);
            }
        },
        OPTIONS {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                return new HttpOptions(request.url);
            }
        },
        TRACE {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                return new HttpTrace(request.url);
            }
        },
        PATCH {
            @Override
            public HttpUriRequest request(HttpRequest request) {
                return new HttpPatch(request.url);
            }
        };

        public abstract HttpUriRequest request(HttpRequest request);
    }

}
